package com.mrx.spring.example.security;

import com.mrx.spring.security.exception.UserNotFoundException;
import com.mrx.spring.security.model.SecurityUser;
import com.mrx.spring.security.service.ISecurityService;
import lombok.SneakyThrows;
import org.hashids.Hashids;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Set;

/**
 * @author Mr.X
 * @since 2023-10-16 15:24
 **/
@Service
public class SecurityService implements ISecurityService {

    private static final String TOKEN_HEADER = "token";

    private static final String SALT = "@#SAAFAW$#@";

    @Resource
    private RedisTokenService redisTokenService;

    /**
     * 使用 token 查找对应的用户信息
     *
     * @param token token, 可能为 null
     * @return token 关联的用户信息, 不能为 null, 找不到就抛出异常 {@link UserNotFoundException}
     */
    @NonNull
    @Override
    public SecurityUser loadUserByToken(String token) {
        if (token == null) {
            throw new UserNotFoundException("Token cannot be null");
        }
        return redisTokenService.loadUserByToken(token)
                .orElseThrow(() -> new UserNotFoundException("Token Expired"));
    }

    /**
     * 获取 token 的 header-key
     *
     * @return token key
     */
    @NonNull
    @Override
    public String tokenHeader() {
        return TOKEN_HEADER;
    }

    /**
     * 不需要校验 token 的 url
     *
     * @return 不需要校验 token 的 url, 不能为 null
     */
    @NonNull
    @Override
    public Set<String> permitUrls() {
        return Set.of("/user/login*", "/test/*", "/task/create", "/task/start");
    }

    /**
     * 是否启用 api 权限校验
     */
    @Override
    public boolean enableApiPermission() {
        return true;
    }

    /**
     * 注入一个 hashIds 的实例, 用以生成随机 token
     *
     * @return hashIds 实例
     */
    @Bean
    @SneakyThrows
    public Hashids hashids() {
        byte[] bytes = new ClassPathResource("assets/proguard-dic.txt").getInputStream().readAllBytes();
        return new Hashids(SALT, 20);
    }

}
